﻿using System;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using WatiN.Core;
using WatiN.Core.Interfaces;
using AttributeConstraint=WatiN.Core.Constraints.AttributeConstraint;

namespace WatiNCF
{
    public abstract class HomePageController<T> : IHomePageController<T>
        where T : class
    {
        private IBrowser _browser;
        private BrowserType _browserType = BrowserType.InternetExplorer;
        private string _baseUrl = string.Empty;
        private string _homePageName = string.Empty;
        

        public BrowserType BrowserType
        {
            get { return _browserType;  }
            set { _browserType = value; }
        }

        /// <summary>
        /// Gets the name of the home page.
        /// </summary>
        /// <value>The name of the home page.</value>
        public string HomePageName
        {
            get { return _homePageName; }
            set { _homePageName = value; }
        }

        /// <summary>
        /// Gets the home page URL.
        /// </summary>
        /// <value>The home page URL.</value>
        public string HomePageUrl
        {
            get
            {
                return BuildUrl(BaseUrl, HomePageName);
            }
        }

        /// <summary>
        /// Gets or sets the parent page.
        /// </summary>
        /// <value>The parent page.</value>
        public IPageController ParentPage
        {
            get { return null; }
            set { throw new System.NotImplementedException("The home pages parent cannot be set."); }
        }

        /// <summary>
        /// Gets the home page.
        /// </summary>
        /// <value>The home page.</value>
        public IHomePageController HomePage
        {
            get { return this; }
        }

        /// <summary>
        /// Gets or sets the browser used by this instance of the home page controller.
        /// </summary>
        /// <value>The browser.</value>
        public IBrowser Browser
        {
            get
            {
                if(_browser == null)
                {
                    try
                    {
                        if (BrowserType == WatiN.Core.BrowserType.InternetExplorer)
                        {
                            BrowserFactory.Settings.AttachToIETimeOut = 3;
                            IE.Settings.AttachToIETimeOut = 3;
                            _browser = IE.AttachToIE(Find.ByUrl(new Regex(BaseUrl + "*")));
                        }
                        else
                        {
                            _browser = BrowserFactory.Create(BrowserType);
                        }
                    }
                    catch (WatiN.Core.Exceptions.IENotFoundException)
                    {
                        _browser = BrowserFactory.Create(BrowserType);
                    }

                    NavigateToHomePage();
                }
                return _browser;
            }
            set { _browser = value; }
        }

        #region Url Handling
        /// <summary>
        /// Navigates to home page.
        /// </summary>
        public void NavigateToHomePage()
        {
            GoToUrl(HomePageUrl);
        }

        

        /// <summary>
        /// Goes to the specified URL, prefixing with "~\" will pre-pend the base url for
        /// the home page controller.
        /// </summary>
        /// <typeparam name="TController">The type of the controller.</typeparam>
        /// <param name="url">The URL to navigate to.</param>
        /// <returns>A new instance of the type of controller</returns>
        public TController GoToUrl<TController>(string url)
            where TController : class, IPageController
        {
            GoToUrl(url);
            return Activator.CreateInstance<TController>();
        }

        /// <summary>
        /// Goes to the specified URL, prefixing with "~\" will pre-pend the base url for 
        /// the home page controller.
        /// </summary>
        /// <param name="url">The URL to navigate to.</param>
        public void GoToUrl(string url)
        {
            const string rootPrefix = @"~";

            if (url.StartsWith(rootPrefix))
            {
                url = url.Replace(rootPrefix, BaseUrl);
            }

            Browser.GoTo(url);
        }

        /// <summary>
        /// Builds a URL using the constituent parts appending any separators where required.
        /// </summary>
        /// <param name="baseUrl">The base URL.</param>
        /// <param name="parts">The parts.</param>
        /// <returns></returns>
        private static string BuildUrl(string baseUrl, params string[] parts)
        {
            const string separator = "/";
            StringBuilder builder = new StringBuilder();
            builder.Append(baseUrl);

            foreach (string part in parts)
            {
                if (!part.StartsWith(separator))
                {
                    builder.Append(separator);
                }
                builder.Append(part);
            }

            return builder.ToString();
        }

        

        /// <summary>
        /// Gets or sets the base URL for the current controller.
        /// </summary>
        /// <value>The base URL.</value>
        public string BaseUrl
        {
            get
            {
                if (_baseUrl == string.Empty)
                {
                    Type type = GetType();
                    if (type.IsDefined(typeof (UrlAttribute), false))
                    {
                        UrlAttribute attr = type.GetCustomAttributes(false).OfType<UrlAttribute>().FirstOrDefault();
                        _baseUrl = attr.BaseUrl;
                        HomePageName = attr.HomePage;
                    }
                }
                return _baseUrl;
            }
            set { _baseUrl = value; }
        }
        #endregion

        public AttributeConstraint ByPartialId(string partialId)
        {
            return WatinFind.ByPartialId(partialId);
        }

        /// <summary>
        /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
        /// </summary>
        public void Dispose()
        {
            if (Browser != null)
            {
                Browser.Dispose();
            }
        }
    }
}
